#include <cv_bridge/cv_bridge.h>
#include <image_transport/image_transport.h>
#include <ros/ros.h>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>

#include <algorithm>
#include <iostream>
#include <list>
#include <stdio.h>
#include <vector>

using namespace std;
using namespace cv;

//函数：Roberts算子实现
Mat Roberts(Mat srcImage);

int main(int argc, char **argv) {
  cv::Mat image = cv::imread(argv[1], CV_LOAD_IMAGE_COLOR);
  // cv::Mat image = cv::imread("/home/bianxu/tools/test.jpg",
  // CV_LOAD_IMAGE_COLOR);
  if (image.empty()) {
    printf("open error\n");
  }
  // cv::imshow("image",image);

  //图像滤波
  // Mat out;
  // 均值滤波
  // blur(image, out, Size(7, 7));  //内核大小Size(7, 7)
  // 高斯滤波
  // GaussianBlur( image, out, Size( 5, 5 ), 0, 0 );  //内核大小Size(5, 5)
  // 中值滤波
  // medianBlur( image, out, 5);   //孔径线性尺寸为5
  // cv::imshow("image1",out);
  // image = out;

  //图像增强
  //直方图均衡化增强
  // Mat imageRGB[3];
  // split(image, imageRGB);
  // for (int i = 0; i < 3; i++)
  // {
  // 	equalizeHist(imageRGB[i], imageRGB[i]);
  // }
  // merge(imageRGB, 3, image);
  // imshow("imageEnhance0", image);

  //拉普拉斯算子增强
  // Mat imageEnhance;
  // Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, 0, 5, 0, 0, -1, 0);
  // filter2D(image, imageEnhance, CV_8UC3, kernel);
  // imshow("imageEnhance1", imageEnhance);

  //对数Log变换增强
  // Mat imageLog(image.size(), CV_32FC3);
  // for (int i = 0; i < image.rows; i++)
  // {
  // 	for (int j = 0; j < image.cols; j++)
  // 	{
  // 		imageLog.at<Vec3f>(i, j)[0] = log(1 + image.at<Vec3b>(i, j)[0]);
  // 		imageLog.at<Vec3f>(i, j)[1] = log(1 + image.at<Vec3b>(i, j)[1]);
  // 		imageLog.at<Vec3f>(i, j)[2] = log(1 + image.at<Vec3b>(i, j)[2]);
  // 	}
  // }
  // //归一化到0~255
  // normalize(imageLog, imageLog, 0, 255, CV_MINMAX);
  // //转换成8bit图像显示
  // convertScaleAbs(imageLog, imageLog);
  // imshow("imageEnhance2", imageLog);

  //伽马变换增强
  Mat imageGamma(image.size(), CV_32FC3);
  for (int i = 0; i < image.rows; i++) {
    for (int j = 0; j < image.cols; j++) {
      imageGamma.at<Vec3f>(i, j)[0] = (image.at<Vec3b>(i, j)[0]) *
                                      (image.at<Vec3b>(i, j)[0]) *
                                      (image.at<Vec3b>(i, j)[0]);
      imageGamma.at<Vec3f>(i, j)[1] = (image.at<Vec3b>(i, j)[1]) *
                                      (image.at<Vec3b>(i, j)[1]) *
                                      (image.at<Vec3b>(i, j)[1]);
      imageGamma.at<Vec3f>(i, j)[2] = (image.at<Vec3b>(i, j)[2]) *
                                      (image.at<Vec3b>(i, j)[2]) *
                                      (image.at<Vec3b>(i, j)[2]);
    }
  }
  //归一化到0~255
  normalize(imageGamma, imageGamma, 0, 255, CV_MINMAX);
  //转换成8bit图像显示
  convertScaleAbs(imageGamma, imageGamma);
  // imshow("imageEnhance3", imageGamma);

  //灰度化
  Mat gray;
  cvtColor(imageGamma, gray, CV_RGB2GRAY);
  // Mat out3 = Roberts(gray); //Roberts边缘检测
  // imshow("imagegray",out3);

  Mat tempImage, dstImage;
  //进行canny边缘检测并转换
  Canny(gray, tempImage, 50, 200, 3);
  cvtColor(tempImage, dstImage, CV_GRAY2BGR);
  // imshow("imagecanny",tempImage);

  //二值化
  // Mat binaryimage;
  // binaryimage = image.clone();
  // //进行二值化处理，选择30，255.0为阈值
  // threshold(out3, binaryimage, 50, 255.0, CV_THRESH_BINARY);
  // //imshow("binaryimage", binaryimage);

  //腐蚀和膨胀操作
  // Mat element = getStructuringElement(MORPH_RECT, Size(2, 2)); //获取自定义核
  // Mat out1, out2;
  // erode(binaryimage,out1, element);   //进行腐蚀操作
  // dilate(out1,out2, element);  //进行膨胀操作
  // imshow("dstimage", out2);

  Mat image1(image.rows, image.cols, image.type(), Scalar(180, 120, 50));
  //霍夫变换圆形检测
  vector<Vec3f> circles;
  HoughCircles(tempImage, circles, CV_HOUGH_GRADIENT, 1, 1, 100, 180, 0, 0);
  int minradius = image.rows;
  Point mincenter;
  //在图中绘制出圆形，取出仪表区域
  for (size_t i = 0; i < circles.size(); i++) {
    //参数定义
    Point center(cvRound(circles[i][0]), circles[i][1]);
    int radius = cvRound(circles[i][2]);
    //绘制圆心
    // circle(image, center, 3, Scalar(0, 255, 0), -1, 8, 0);
    //绘制圆形轮廓
    // circle(image, center, radius, Scalar(0, 0, 255), 3, 8, 0);
    if (radius < minradius) {
      minradius = radius;
      mincenter = center;
    }
    for (int x = 0; x < image.cols; x++) {
      for (int y = 0; y < image.rows; y++) {
        int temp =
            ((x - center.x) * (x - center.x) + (y - center.y) * (y - center.y));
        if (temp < (radius * radius)) {
          image1.at<Vec3b>(Point(x, y))[0] =
              imageGamma.at<Vec3b>(Point(x, y))[0];
          image1.at<Vec3b>(Point(x, y))[1] =
              imageGamma.at<Vec3b>(Point(x, y))[1];
          image1.at<Vec3b>(Point(x, y))[2] =
              imageGamma.at<Vec3b>(Point(x, y))[2];
        }
      }
    }
  }
  //取最小圆为仪表刻度盘
  circle(image1, mincenter, 3, Scalar(0, 255, 0), -1, 8, 0);
  circle(image1, mincenter, minradius, Scalar(0, 0, 255), 3, 8, 0);

  //霍夫变换直线检测
  vector<Vec4i> lines; //定义一个矢量结构lines用于存放得到的线段矢量集合
  HoughLinesP(tempImage, lines, 1, CV_PI / 180, 80, 120, 8);
  //在圆中依次绘制出每条线段
  for (size_t i = 0; i < lines.size(); i++) {
    Vec4i l = lines[i];
    int temp1 = ((l[0] - mincenter.x) * (l[0] - mincenter.x) +
                 (l[1] - mincenter.y) * (l[1] - mincenter.y));
    int temp2 = ((l[2] - mincenter.x) * (l[2] - mincenter.x) +
                 (l[3] - mincenter.y) * (l[3] - mincenter.y));
    if (temp1 < (minradius * minradius) || temp2 < (minradius * minradius)) {
      line(image1, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1,
           CV_AA);
    }
  }
  imshow("HoughFind", image1);

  Mat dstImage1;
  medianBlur(image1, image1, 3); //中值滤波,孔径线性尺寸为3
  cvtColor(image1, dstImage1, CV_RGB2GRAY);
  Canny(dstImage1, dstImage1, 50, 200, 3);
  imshow("HoughFind1", dstImage1);

  cv::waitKey(0);
}

//边缘检测函数：Roberts算子实现
Mat Roberts(Mat srcImage) {
  Mat dstImage = srcImage.clone();
  int rowsNum = srcImage.rows;
  int colsNum = srcImage.cols;
  for (int i = 0; i < rowsNum - 1; i++) {
    for (int j = 0; j < colsNum - 1; j++) {
      //根据公式进行计算
      int t1 = (srcImage.at<uchar>(i, j) - srcImage.at<uchar>(i + 1, j + 1)) *
               (srcImage.at<uchar>(i, j) - srcImage.at<uchar>(i + 1, j + 1));
      int t2 = (srcImage.at<uchar>(i + 1, j) - srcImage.at<uchar>(i, j + 1)) *
               (srcImage.at<uchar>(i + 1, j) - srcImage.at<uchar>(i, j + 1));
      //计算对角线像素差
      dstImage.at<uchar>(i, j) = (uchar)sqrt(t1 + t2);
    }
  }
  return dstImage;
}
